package com.cia.blockchain;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.fisco.bcos.sdk.abi.FunctionReturnDecoder;
import org.fisco.bcos.sdk.abi.TypeReference;
import org.fisco.bcos.sdk.abi.datatypes.Function;
import org.fisco.bcos.sdk.abi.datatypes.Type;
import org.fisco.bcos.sdk.abi.datatypes.Utf8String;
import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2;
import org.fisco.bcos.sdk.client.Client;
import org.fisco.bcos.sdk.contract.Contract;
import org.fisco.bcos.sdk.crypto.CryptoSuite;
import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair;
import org.fisco.bcos.sdk.model.CryptoType;
import org.fisco.bcos.sdk.model.TransactionReceipt;
import org.fisco.bcos.sdk.model.callback.TransactionCallback;
import org.fisco.bcos.sdk.transaction.model.exception.ContractException;

@SuppressWarnings("unchecked")
public class KeyValueStorage extends Contract {
    public static final String[] BINARY_ARRAY = {"608060405234801561001057600080fd5b5061054a806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680631e7c019714610051578063693ec85e14610100575b600080fd5b34801561005d57600080fd5b506100fe600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506101e2565b005b34801561010c57600080fd5b50610167600480360381019080803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506102e9565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101a757808201518184015260208101905061018c565b50505050905090810190601f1680156101d45780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6000826040516020018082805190602001908083835b60208310151561021d57805182526020820191506020810190506020830392506101f8565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b6020831015156102865780518252602082019150602081019050602083039250610261565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020905081600080836000191660001916815260200190815260200160002090805190602001906102e3929190610479565b50505050565b60606000826040516020018082805190602001908083835b6020831015156103265780518252602082019150602081019050602083039250610301565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b60208310151561038f578051825260208201915060208101905060208303925061036a565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020905060008082600019166000191681526020019081526020016000208054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561046c5780601f106104415761010080835404028352916020019161046c565b820191906000526020600020905b81548152906001019060200180831161044f57829003601f168201915b5050505050915050919050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106104ba57805160ff19168380011785556104e8565b828001600101855582156104e8579182015b828111156104e75782518255916020019190600101906104cc565b5b5090506104f591906104f9565b5090565b61051b91905b808211156105175760008160009055506001016104ff565b5090565b905600a165627a7a72305820efe28d8571195ba8f6fab1ad41a455ffa5114f1395e897375fdc87d5e8d4debf0029"};

    public static final String BINARY = org.fisco.bcos.sdk.utils.StringUtils.joinAll("", BINARY_ARRAY);

    public static final String[] SM_BINARY_ARRAY = {"608060405234801561001057600080fd5b5061054a806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680637b1b8e0314610051578063c9077b0d14610133575b600080fd5b34801561005d57600080fd5b506100b8600480360381019080803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506101e2565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f85780820151818401526020810190506100dd565b50505050905090810190601f1680156101255780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561013f57600080fd5b506101e0600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610372565b005b60606000826040516020018082805190602001908083835b60208310151561021f57805182526020820191506020810190506020830392506101fa565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b6020831015156102885780518252602082019150602081019050602083039250610263565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020905060008082600019166000191681526020019081526020016000208054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156103655780601f1061033a57610100808354040283529160200191610365565b820191906000526020600020905b81548152906001019060200180831161034857829003601f168201915b5050505050915050919050565b6000826040516020018082805190602001908083835b6020831015156103ad5780518252602082019150602081019050602083039250610388565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b60208310151561041657805182526020820191506020810190506020830392506103f1565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902090508160008083600019166000191681526020019081526020016000209080519060200190610473929190610479565b50505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106104ba57805160ff19168380011785556104e8565b828001600101855582156104e8579182015b828111156104e75782518255916020019190600101906104cc565b5b5090506104f591906104f9565b5090565b61051b91905b808211156105175760008160009055506001016104ff565b5090565b905600a165627a7a723058201f4bd8045f86e47377c9d5fc9606b9d2b23b66cf9f4e579f065d6bde2a8636fc0029"};

    public static final String SM_BINARY = org.fisco.bcos.sdk.utils.StringUtils.joinAll("", SM_BINARY_ARRAY);

    public static final String[] ABI_ARRAY = {"[{\"constant\":false,\"inputs\":[{\"name\":\"key\",\"type\":\"string\"},{\"name\":\"value\",\"type\":\"string\"}],\"name\":\"write\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"key\",\"type\":\"string\"}],\"name\":\"get\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]"};

    public static final String ABI = org.fisco.bcos.sdk.utils.StringUtils.joinAll("", ABI_ARRAY);

    public static final String FUNC_WRITE = "write";

    public static final String FUNC_GET = "get";

    protected KeyValueStorage(String contractAddress, Client client, CryptoKeyPair credential) {
        super(getBinary(client.getCryptoSuite()), contractAddress, client, credential);
    }

    public static String getBinary(CryptoSuite cryptoSuite) {
        return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY);
    }

    public TransactionReceipt write(String key, String value) {
        final Function function = new Function(
                FUNC_WRITE, 
                Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(key), 
                new org.fisco.bcos.sdk.abi.datatypes.Utf8String(value)), 
                Collections.<TypeReference<?>>emptyList());
        return executeTransaction(function);
    }

    public byte[] write(String key, String value, TransactionCallback callback) {
        final Function function = new Function(
                FUNC_WRITE, 
                Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(key), 
                new org.fisco.bcos.sdk.abi.datatypes.Utf8String(value)), 
                Collections.<TypeReference<?>>emptyList());
        return asyncExecuteTransaction(function, callback);
    }

    public String getSignedTransactionForWrite(String key, String value) {
        final Function function = new Function(
                FUNC_WRITE, 
                Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(key), 
                new org.fisco.bcos.sdk.abi.datatypes.Utf8String(value)), 
                Collections.<TypeReference<?>>emptyList());
        return createSignedTransaction(function);
    }

    public Tuple2<String, String> getWriteInput(TransactionReceipt transactionReceipt) {
        String data = transactionReceipt.getInput().substring(10);
        final Function function = new Function(FUNC_WRITE, 
                Arrays.<Type>asList(), 
                Arrays.<TypeReference<?>>asList(new TypeReference<Utf8String>() {}, new TypeReference<Utf8String>() {}));
        List<Type> results = FunctionReturnDecoder.decode(data, function.getOutputParameters());
        return new Tuple2<String, String>(

                (String) results.get(0).getValue(), 
                (String) results.get(1).getValue()
                );
    }

    public String get(String key) throws ContractException {
        final Function function = new Function(FUNC_GET, 
                Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(key)), 
                Arrays.<TypeReference<?>>asList(new TypeReference<Utf8String>() {}));
        return executeCallWithSingleValueReturn(function, String.class);
    }

    public static KeyValueStorage load(String contractAddress, Client client, CryptoKeyPair credential) {
        return new KeyValueStorage(contractAddress, client, credential);
    }

    public static KeyValueStorage deploy(Client client, CryptoKeyPair credential) throws ContractException {
        return deploy(KeyValueStorage.class, client, credential, getBinary(client.getCryptoSuite()), "");
    }
}
